#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include <time.h>
#include <sys/socket.h>
#include <getopt.h>

#include "sqlite3.h"
#include "get_temp.h"
#include "get_ID.h"
#include "select.h"
#include "insert.h"

static int  go_stop = 0;

void print_usage(char *programe)
{
	printf("%s usage: \n",programe);
	printf("-i(--ipaddr): specify server IP address\n");
	printf("-p(--port): specify server port\n");
	printf("-t(--interval): time to send\n");
	printf("-h(--help): print this help information\n");
	return;
}

void print_usage(char *programe);
int sqlite_init(sqlite3  **db);
int check_connected(int sockfd);
int socket_conn_init(char *IP, int PORT, int *sockfd);
int check_sample_time(time_t  *last_time, int interval);

int main (int argc,char ** argv)
{
	int                     on = -1;
	int                     ch = -1;
	int                     rv = -1;
	int                     sv = -1;
	int                     wv = -1;
	int                     PORT;
	int                     sockfd = -1;
	int                     connfd = -1;
	int                     interval;
	int                     get_new = 0;
	int                     get_disconnect = 0;
	
	time_t                  last_time;     
	time_t                  rawtime;
	

	sqlite3                 *db = NULL;
	char                    *errmsg = NULL;
	char                    *dbResult = NULL;
	
	char                    read_buf[1024] = {};
	char                    buffer[80] = {};
	char                    time_temp[128] = {};
	char                    *IP = NULL;

	struct                  tm *info;
	
	struct sockaddr_in      serv_addr = {};
	struct rpi_ID_s         rpi_ID = {};
	struct rpi_data_s       rpi_data = {};
	struct  tcp_info        t_info;
	int	                    len=sizeof(t_info);
	
	struct option opts[] ={
		{"ipaddr", required_argument, NULL,'i'},
		{"port", required_argument, NULL, 'p'},
		{"interval", required_argument, NULL, 't'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	while((ch= getopt_long(argc,argv,  "i:p:t:h", opts,NULL))!= -1)
	{
		switch(ch)
		{
			case'i':
				IP = optarg;
				break;
			case'p':
				PORT = atoi(optarg);
				break;
			case't':
				interval = atoi(optarg);
				break;
			case'h':
				print_usage(argv[0]);
				return 0;
		}
	}

	if(!IP || !PORT || !interval)
	{
		print_usage(argv[0]);
		return 0;
	}

	printf("start socket......\n");
	//socket初始化连接
	if(connfd = socket_conn_init(IP, PORT, &sockfd) <0)
	{
		printf("socket_conn_init failure:%s\n", strerror(errno));
		return 0;
	}
	printf("connect to server successful!\n");
	
	//数据库初始化
	if((sqlite_init(&db)))
	{
		printf("sqlite_init failure:%s\n", strerror(errno));
		goto clean;
	}
	printf("sqlite_init successful!\n");

	while(!go_stop)
	{
		printf("into while!\n");

		if(check_sample_time(&last_time, interval) == 1)
		{
			get_new = 1;
		}
		else
		{
			get_new = 0;
		}
		printf("get_new:%d\n", get_new);

		if(check_connected(sockfd) == 0)
		{
			get_disconnect = 0;
		}
		else
		{
			get_disconnect = 1;
		}
		printf("get_disconnect:%d\n", get_disconnect);
		
		if(get_new == 1)
		{
			if(get_disconnect == 0)
			{
				printf("Start get new message to publish!\n");

				time( &rawtime );
				info =localtime( &rawtime );

				rv = get_temperature(&rpi_data);
				if(rv<0)
				{
					printf("get time failure,return value:%d\n",rv);
					return -1;
				}

				rv =  get_ID(&rpi_ID);
				if(rv<0)
				{
					printf("get ID failure,return value:%d\n",rv);
					return -2;
				}

				snprintf(time_temp, sizeof(time_temp),"%s/%s/%4.2f",rpi_ID.ID, asctime(info), rpi_data.temp);
				printf("time_temp:%s\n", time_temp);

				wv=write(sockfd, time_temp, sizeof(time_temp));
				if(wv<0)
				{
					printf("Write to IP[%s]:port[%d] failure:%s\n", IP, PORT, strerror(errno));
					return -1;
				}
				printf("Write to IP[%s]:port[%d] successful!\n", IP, PORT);

				sleep(10);
			}

			if(get_disconnect == 1)
			{
				printf("Get disconnect with IP[%s]:port[%d]!\n", IP, PORT);
				printf("Start get new message to insert!\n");

				rv = sqlite_insert(&db);
				if(rv)
				{
					printf("sqlite3_insert failure:%s\n", strerror(errno));
					return -1;
				}
				printf("insert ok!\n");

				connfd = socket_conn_init(IP, PORT, &sockfd);
				if(connfd < 0)
				{
					printf("[198]Connect to server failure:%s\n",strerror(errno));
				}
				
				sleep(10);
			}
		}

		if(get_new == 0)
		{
			if(get_disconnect == 0)
			{
				printf("Start select old message to publish!\n");
				
				sv = sqlite_select(&db, &dbResult);
				if(sv < 0)
				{
					printf("select failure:%s\n", strerror(errno));
					return -1;
				}
				else if(sv == 0)
				{
					wv=write(sockfd, &dbResult, sizeof(dbResult));
					if(wv<0)
					{
						printf("Write dbResult to IP[%s]:port[%d] failure:%s\n", IP, PORT, strerror(errno));
						return -1;
					}
					printf("Write dbResult to IP[%s]:port[%d] successful!\n", IP, PORT);
				}
				sleep(10);
			}

			if(get_disconnect == 1)
			{
				printf("Get disconnect with IP[%s]:port[%d]!\n", IP, PORT);
				printf("Just reconnect!\n");

				connfd = socket_conn_init(IP, PORT, &sockfd);
				if(connfd < 0)
				{
					printf("[239]Connect to server failure:%s\n",strerror(errno));
				}
				
				sleep(10);
			}
		}
	}
clean:
	sqlite3_close(db);
	close(sockfd);
	return 0;

}

int socket_conn_init(char *IP, int PORT, int *sockfd)
{
	int                   on = -1;
	int                   connfd = -1;
	struct sockaddr_in    serv_addr;

	if((*sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0 )
	{
		printf("Socket failure:%s\n", strerror(errno));
		return -1;
	}
	printf("Socket seccessful! sockfd[%d]\n", *sockfd);

	memset(&serv_addr, 0 ,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	inet_aton(IP, &serv_addr.sin_addr);

	setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	if((connfd=connect(*sockfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr) )<0))
	{
		printf("[275]Connect to server failure:%s\n",strerror(errno));
		return -1;
	}
	return 0;
}

int sqlite_init(sqlite3  **db)
{
	int           rv = -1;
	char          *errmsg = NULL;


	printf("start sqlite3.....\n");
	rv=sqlite3_open("ds18b20.db", db);
	if(rv!=SQLITE_OK)
	{
		printf("Open db failure:%s\n", sqlite3_errmsg(*db));
		return -1;
	}
	printf("Open db successful!\n");

	rv=sqlite3_exec(*db, "create table if not exists temp(num INTEGER PRIMARY KEY, ID TEXT , time TEXT, temperature REAL)", NULL, NULL, &errmsg);
	if(rv!=SQLITE_OK)
	{
		printf("Create table failure:%s\n", errmsg);
		return -1;
	}
	printf("Create table successful!\n");

	return 0;
}

int check_connected(int sockfd)
{
	struct tcp_info    info;
	int                len;


	len = sizeof(info);
	if(sockfd <=0 )
	{
		printf("disconnect now!\n");
		return -1;
	}

	if(getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&len) <0 )
	{
		printf("getsockopt() TCP_INFO error:%s\n", strerror(errno));
		return -1;
	}

	if(info.tcpi_state == 1)
	{
		printf("keep connect!\n");
		return 0;
	}
	else
	{
		printf("get disconnect!\n");
		return 1;
	}
}

int check_sample_time(time_t  *last_time, int interval)
{
	int         get_data = 0;
	time_t      now;

	if(now >= *last_time+interval)
	{
		get_data = 1;
		*last_time = now;
	}

	return get_data;
}
